/*! \file pscheduler.c
   Implement the preemptive scheduler here. 
 */

/*
 * Note that the timer queue holds the block processes.
 * The code in timer_interrupt_handler, above where this file is #included, 
 * will periodically check if any of the blocked processes can be put in the ready queue.
 * If a process is not blocked anymore (its timer expired), then it can be run.
 * When it can be run, it will be either run directly (when the ready queue is empty) 
 * or queued in the ready queue (if multiple threads are running)
 */


	/* This gets run every 1/200Hz = 5msec due to the clock-interrupt.
	 * This means we should decrement the currently running threads timeslice, as 1 unit (=5msec) has passed. */
	cpu_private_data.ticks_left_of_time_slice--;

	/* Check if timeslice has been used up */
	if (cpu_private_data.ticks_left_of_time_slice <= 0) 
	{
		/* The timeslice has been used up, so we must find another thread to run. */
		
		if (cpu_private_data.thread_index != -1) {
			/* We have an actual still-running thread (ie. not the idle-thread),
			 * put it back back the ready queue. => Remember to run it again later.
			 * The idle-thread should never be added to our thread queue; 
			 * it should only be run when the thread-queue is empty! */
			thread_queue_enqueue(&ready_queue, cpu_private_data.thread_index);
		}

		if (!thread_queue_is_empty(&ready_queue)) {
			/* Pop the head-thread off, and run it */
			int head_thread = thread_queue_dequeue(&ready_queue);
			cpu_private_data.thread_index = head_thread;
			cpu_private_data.ticks_left_of_time_slice = 4;	// Give it 4 units to run in before next context switch
		} else {
			/* Thread-queue is empty, so run the idle thread */
			cpu_private_data.thread_index = -1;				// -1 is the idle-thread
			cpu_private_data.ticks_left_of_time_slice = 1;	// Make the idle thread thin
		}		
	}
